home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / admin / dig-2.0 / dig-2 / dig.2.0 / res_send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-04  |  9.3 KB  |  441 lines

  1.  
  2. /*
  3.  * Copyright (c) 1985 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that this notice is preserved and that due credit is given
  8.  * to the University of California at Berkeley. The name of the University
  9.  * may not be used to endorse or promote products derived from this
  10.  * software without specific prior written permission. This software
  11.  * is provided ``as is'' without express or implied warranty.
  12.  */
  13.  
  14. /*
  15. ** Modified for and distributed with 'dig' version 2.0 from
  16. ** University of Southern California Information Sciences Institute
  17. ** (USC-ISI). 9/1/90
  18. */
  19.  
  20.  
  21. #if defined(LIBC_SCCS) && !defined(lint)
  22. static char sccsid[] = "@(#)res_send.c    6.19 (Berkeley) 3/7/88";
  23. #endif /* LIBC_SCCS and not lint */
  24.  
  25. /*
  26.  * Send query to name server and wait for reply.
  27.  */
  28.  
  29. #include "hfiles.h"
  30. #include PARAMH
  31. #include <sys/socket.h>
  32. #include <sys/uio.h>
  33. #include <netinet/in.h>
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include NAMESERH
  37. #ifndef T_TXT
  38. #define T_TXT 16
  39. #endif T_TXT
  40. #include RESOLVH
  41. #include "qtime.h"
  42. #include "pflag.h"
  43. extern int errno;
  44. extern int eecode;
  45.  
  46. static int s = -1;    /* socket used for communications */
  47. static struct sockaddr no_addr;
  48. static int old_conn;
  49.   
  50. #define RES_DEBUG2      0x80000000
  51.  
  52. #ifndef FD_SET
  53. #define    NFDBITS        32
  54. #define    FD_SETSIZE    32
  55. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  56. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  57. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  58. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  59. #endif
  60.  
  61. #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
  62.  
  63. res_send(buf, buflen, answer, anslen)
  64.     char *buf;
  65.     int buflen;
  66.     char *answer;
  67.     int anslen;
  68. {
  69.     register int n;
  70.     int retry, v_circuit, resplen, ns;
  71.     int gotsomewhere = 0, connected = 0;
  72.     u_short id, len;
  73.     int conn;
  74.     char *cp;
  75.     fd_set dsmask;
  76.     struct timeval timeout, ftime, htime;
  77.     HEADER *hp = (HEADER *) buf;
  78.     HEADER *anhp = (HEADER *) answer;
  79.     struct iovec iov[2];
  80.     int terrno = ETIMEDOUT;
  81.     char junk[512];
  82.         int retval = 0;
  83.  
  84. #ifdef DEBUG
  85.     if (pfcode & PRF_QUERY) {
  86.         p_query(buf);
  87.     }
  88. #endif DEBUG
  89.     if (!(_res.options & RES_INIT))
  90.         if (res_init() == -1) {
  91.             return(-99);
  92.         }
  93.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  94.     id = ntohs(hp->id); hp->id = htons(id-1);
  95.     conn = (_res.options & RES_STAYOPEN);
  96.     if ((s>=0) && (old_conn) && !(conn)) {
  97.       (void) close(s);
  98.       s = (-1);
  99.     }
  100.     old_conn = conn;
  101.  
  102.     /*
  103.      * Send request, RETRY times, or until successful
  104.      */
  105.     for (retry = _res.retry; retry > 0; retry--) {
  106.        for (ns = 0; ns < _res.nscount; ns++) {
  107.          hp->id = htons(ntohs(hp->id)+1);
  108. #ifdef DEBUG
  109.         if (_res.options & RES_DEBUG2)
  110.           printf(";; Querying server (# %d) address = %s\n", ns+1,
  111.                   inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  112. #endif DEBUG
  113.         if (v_circuit) {
  114.             int truncated = 0;
  115.  
  116.             /*
  117.              * Use virtual circuit.
  118.              */
  119.  
  120. (void) gettimeofday(&htime,NULL);
  121. savetime(hp->id,&htime);
  122.  
  123.             if (s < 0) {
  124.                 s = socket(AF_INET, SOCK_STREAM, 0);
  125.                 if (s < 0) {
  126.                     terrno = errno;
  127. #ifdef DEBUG
  128.                     if (_res.options & RES_DEBUG)
  129.                         perror(";; socket failed");
  130. #endif DEBUG
  131.                     continue;
  132.                 }
  133.                 if (connect(s, &(_res.nsaddr_list[ns]),
  134.                    sizeof(struct sockaddr)) < 0) {
  135.                     terrno = errno;
  136. #ifdef DEBUG
  137.                     if (_res.options & RES_DEBUG)
  138.                         perror(";; connect failed");
  139. #endif DEBUG
  140.                     (void) close(s);
  141.                     s = -1;
  142.                     continue;
  143.                 }
  144.             }
  145.             /*
  146.              * Send length & message
  147.              */
  148.             len = htons((u_short)buflen);
  149.             iov[0].iov_base = (caddr_t)&len;
  150.             iov[0].iov_len = sizeof(len);
  151.             iov[1].iov_base = buf;
  152.             iov[1].iov_len = buflen;
  153.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  154.                 terrno = errno;
  155. #ifdef DEBUG
  156.                 if (_res.options & RES_DEBUG)
  157.                     perror(";; write failed");
  158. #endif DEBUG
  159.                 (void) close(s);
  160.                 s = -1;
  161.                 continue;
  162.             }
  163.  
  164.  
  165. #ifdef DEBUG
  166.                 if (_res.options & RES_DEBUG2) {
  167.               printf(";; id = %d - sending now: ",ntohs(hp->id));
  168.                   prnttime(&htime);
  169.                   printf("\n");
  170.                 }
  171. #endif DEBUG
  172.             /*
  173.              * Receive length & response
  174.              */
  175.             cp = answer;
  176.             len = sizeof(short);
  177.             while (len != 0 &&
  178.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  179.                 cp += n;
  180.                 len -= n;
  181.             }
  182.  
  183. (void) gettimeofday(&ftime, NULL);
  184.  
  185.             if (n <= 0) {
  186.                 terrno = errno;
  187. #ifdef DEBUG
  188.                 if (_res.options & RES_DEBUG)
  189.                     perror(";; read failed");
  190. #endif DEBUG
  191.                 (void) close(s);
  192.                 s = -1;
  193.                 continue;
  194.             }
  195.             cp = answer;
  196.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  197. #ifdef DEBUG
  198.                 if (_res.options & RES_DEBUG)
  199.                     fprintf(stderr, ";; response truncated\n");
  200. #endif DEBUG
  201.                 len = anslen;
  202.                 truncated = 1;
  203.             } else
  204.                 len = resplen;
  205.             while (len != 0 &&
  206.                (n = read(s, (char *)cp, (int)len)) > 0) {
  207.                 cp += n;
  208.                 len -= n;
  209.             }
  210.  
  211.             if (n <= 0) {
  212.                 terrno = errno;
  213. #ifdef DEBUG
  214.                 if (_res.options & RES_DEBUG)
  215.                     perror(";; read failed");
  216. #endif DEBUG
  217.                 (void) close(s);
  218.                 s = -1;
  219.                 continue;
  220.             }
  221.  
  222.             if (truncated) {
  223.                 /*
  224.                  * Flush rest of answer
  225.                  * so connection stays in synch.
  226.                  */
  227.                 anhp->tc = 1;
  228.                 len = resplen - anslen;
  229.                 while (len != 0) {
  230.                     n = (len > sizeof(junk) ?
  231.                         sizeof(junk) : len);
  232.                     if ((n = read(s, junk, n)) > 0)
  233.                         len -= n;
  234.                     else
  235.                         break;
  236.                       }
  237.                   }
  238.         } else {
  239.             /*
  240.              * Use datagrams.
  241.              */
  242.             if (s < 0)
  243.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  244. #if    BSD >= 43
  245.             if (_res.nscount == 1 || retry == _res.retry) {
  246.                 /*
  247.                  * Don't use connect if we might
  248.                  * still receive a response
  249.                  * from another server.
  250.                  */
  251.                 if (connected == 0) {
  252.                     if (connect(s, &_res.nsaddr_list[ns],
  253.                         sizeof(struct sockaddr)) < 0) {
  254. #ifdef DEBUG
  255.                         if (_res.options & RES_DEBUG)
  256.                             perror(";; connect");
  257. #endif DEBUG
  258.                         continue;
  259.                     }
  260.                     connected = 1;
  261.                 }
  262.                 if (send(s, buf, buflen, 0) != buflen) {
  263. #ifdef DEBUG
  264.                     if (_res.options & RES_DEBUG)
  265.                         perror(";; send");
  266. #endif DEBUG
  267.                     continue;
  268.                 }
  269.             } else
  270. #endif BSD
  271.  
  272.             if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
  273.                 sizeof(struct sockaddr)) != buflen) {
  274. #ifdef DEBUG
  275.                 if (_res.options & RES_DEBUG)
  276.                     perror(";; sendto");
  277. #endif DEBUG
  278.                 continue;
  279.                   }
  280.  
  281. (void) gettimeofday(&htime,NULL);
  282. savetime(hp->id,&htime);
  283.  
  284.             /*
  285.              * Wait for reply
  286.              */
  287.  
  288. #ifdef DEBUG
  289.                 if (_res.options & RES_DEBUG2) {
  290.               printf(";; id = %d - sending now: ",ntohs(hp->id));
  291.                   prnttime(&htime);
  292.                   printf("\n");
  293.                 }
  294. #endif DEBUG
  295.  
  296.             timeout.tv_sec = (_res.retrans << (_res.retry - retry))
  297.                 / _res.nscount;
  298.             if (timeout.tv_sec <= 0)
  299.                 timeout.tv_sec = 1;
  300.             timeout.tv_usec = 0;
  301. wait:
  302.             FD_ZERO(&dsmask);
  303.             FD_SET(s, &dsmask);
  304.             n = select(s+1, &dsmask, (fd_set *)NULL,
  305.                 (fd_set *)NULL, &timeout);
  306.             if (n < 0) {
  307. #ifdef DEBUG
  308.                 if (_res.options & RES_DEBUG)
  309.                     perror(";; select");
  310. #endif DEBUG
  311.                 continue;
  312.             }
  313.             if (n == 0) {
  314.                 /*
  315.                  * timeout
  316.                  */
  317. #ifdef DEBUG
  318.                 if (_res.options & RES_DEBUG2) {
  319.                     printf(";; timeout at: ");
  320.                     (void) gettimeofday(&ftime, NULL);
  321.                     prnttime(&ftime);
  322.                     printf("\n");
  323.                       }
  324. #endif DEBUG
  325.                 /*
  326.                  * Disconnect if we want to listen
  327.                  * for responses from more than one server.
  328.                  */
  329.                 if (_res.nscount > 1 && connected) {
  330.                     (void) connect(s, &no_addr,
  331.                         sizeof(no_addr));
  332.                     connected = 0;
  333.                 }
  334.                 gotsomewhere = 1;
  335.                 continue;
  336.                   }
  337.  
  338. (void) gettimeofday(&ftime,NULL);
  339.  
  340.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  341. #ifdef DEBUG
  342.                 if (_res.options & RES_DEBUG)
  343.                     perror(";; recvfrom");
  344. #endif DEBUG
  345.                 continue;
  346.             }
  347.             gotsomewhere = 1;
  348.  
  349.             if (id > anhp->id) {
  350.                 /*
  351.                  * response from old query, ignore it
  352.                  */
  353. #ifdef DEBUG
  354.               if (_res.options & RES_DEBUG) {
  355.                 printf(";****; Old Answer id: %d\n",anhp->id);
  356.                 }
  357. #endif DEBUG
  358.                 goto wait;
  359.             }
  360.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  361.                 /*
  362.                  * get rest of answer
  363.                  */
  364. #ifdef DEBUG
  365.                 if (_res.options & RES_DEBUG)
  366.                     printf(";; truncated answer\n");
  367. #endif DEBUG
  368.                 (void) close(s);
  369.                 s = -1;
  370.                 /*
  371.                  * retry decremented on continue
  372.                  * to desired starting value
  373.                  */
  374.                 retry = _res.retry + 1;
  375.                 v_circuit = 1;
  376.                 continue;
  377.             }
  378.          }
  379.  
  380.          difftv(&ftime,findtime(anhp->id),&hqtime);
  381.          hqcount = ntohs(hp->id) - _res.id + 1;
  382.          hxcount = ntohs(hp->id) - ntohs(anhp->id);
  383.  
  384.          _res.id = ntohs(hp->id);
  385.              eecode = retval = anhp->rcode;
  386.          if (retval)
  387.            retval = 0 - retval;
  388.  
  389. #ifdef DEBUG
  390.         if (pfcode & PRF_REPLY) {
  391.             p_query(answer);
  392.         }
  393. #endif DEBUG
  394.         /*
  395.          * We are going to assume that the first server is preferred
  396.          * over the rest (i.e. it is on the local machine) and only
  397.          * keep that one open.
  398.          */
  399.         if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
  400.             return (resplen);
  401.         } else {
  402.             (void) close(s);
  403.             s = -1;
  404.             return (resplen);
  405.         }
  406.        }
  407.     }
  408.     if (s >= 0) {
  409.         (void) close(s);
  410.         s = -1;
  411.     }
  412.     if (v_circuit == 0) {
  413.         if (gotsomewhere == 0) {
  414.                         eecode = 6;
  415.             errno = ECONNREFUSED;
  416.               } else {
  417.             errno = ETIMEDOUT;
  418.             eecode = 7;
  419.               }
  420.           }    else {
  421.         errno = terrno;
  422.         eecode = 8;
  423.           }
  424.     return (-99);
  425.       }
  426.  
  427. /*
  428.  * This routine is for closing the socket if a virtual circuit is used and
  429.  * the program wants to close it.  This provides support for endhostent()
  430.  * which expects to close the socket.
  431.  *
  432.  * This routine is not expected to be user visible.
  433.  */
  434. _res_close()
  435. {
  436.     if (s != -1) {
  437.         (void) close(s);
  438.         s = -1;
  439.     }
  440. }
  441.